package com.bysc.commentservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bysc.baseservice.handler.BaiYunException;
import com.bysc.commentservice.client.UserClient;
import com.bysc.commentservice.entity.CommentPost;
import com.bysc.commentservice.entity.vo.CommentQueryVo;
import com.bysc.commentservice.entity.vo.PostFormVo;
import com.bysc.commentservice.mapper.CommentPostMapper;
import com.bysc.commentservice.service.CommentPostService;
import com.bysc.commentservice.utils.CommentService;
import com.bysc.commentservice.utils.RedisUtils;
import com.bysc.commonutils.ResultCode;
import com.bysc.commonutils.constant.MessageConstant;
import com.bysc.commonutils.utils.DateUtil;
import com.bysc.commonutils.vo.PageResult;
import com.bysc.commonutils.vo.UserInfoVo;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import static com.bysc.commonutils.constant.RedisConstant.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author kkk
 * @since 2024-06-15
 */
@Service
@Slf4j
public class CommentPostServiceImpl extends ServiceImpl<CommentPostMapper, CommentPost> implements CommentPostService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserClient userClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private CommentService commentService;
    @Autowired
    private RedisUtils redisUtils;


    @Override
    public CommentPost addPostByToken(PostFormVo postFormVo, String userId) {

        CommentPost commentPost = new CommentPost();
        BeanUtils.copyProperties(postFormVo, commentPost);
        commentPost.setUserId(userId);
        commentPost.setIsDeleted(false);
        commentPost.setGmtCreate(new Date());
        commentPost.setGmtModified(new Date());
        CommentPost insert = mongoTemplate.insert(commentPost);
        return insert;
    }


    @Override
    public void updatePost(PostFormVo postFormVo, Object id) {
        if (!ObjectUtils.isEmpty(postFormVo)) {
            String postImage = postFormVo.getPostImage();
            String content = postFormVo.getContent();
            String typeId = postFormVo.getTypeId();
            Boolean isPrivate = postFormVo.getIsPrivate();
            String parentTypeId = postFormVo.getParentTypeId();
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(id));
            query.addCriteria(Criteria.where("isDeleted").is(false));
            CommentPost commentPost = mongoTemplate.findOne(query, CommentPost.class);
            if (ObjectUtils.isEmpty(commentPost)) {
                throw new BaiYunException(ResultCode.ERROR, "此帖子不存在");
            }
            Update update = new Update();
            update.set("postImage", postImage);
            update.set("content", content);
            update.set("typeId", typeId);
            update.set("parentTypeId", parentTypeId);
            update.set("isPrivate", isPrivate);
            update.set("gmtModified", new Date());

            UpdateResult result = null;
            try {
                result = mongoTemplate.updateFirst(query, update, CommentPost.class);
            } catch (Exception e) {
                e.printStackTrace();
                throw new BaiYunException(ResultCode.ERROR, e.getMessage());
            }
            log.info("更新帖子,详细信息：{}", result);
        }
    }

    @Override
    public CommentPost deletePost(Object id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        CommentPost commentPost = mongoTemplate.findOne(query, CommentPost.class);
        if (ObjectUtils.isEmpty(commentPost)) {
            throw new BaiYunException(ResultCode.ERROR, "此帖子不存在");
        }
        Update update = new Update();
        update.set("isDeleted", true);
        UpdateResult remove = null;
        try {
            remove = mongoTemplate.updateFirst(query, update, CommentPost.class);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaiYunException(ResultCode.ERROR, e.getMessage());
        }
        log.info("删除帖子帖子,详细信息：{}", remove);
        return commentPost;
    }


    @Override
    public PageResult getPostListByCommentQueryVoAndTokenOrderByCreatTime(String userId, Integer page, Integer limit, CommentQueryVo queryVo) {

        String typeId = queryVo.getTypeId();
        String typePId = queryVo.getPTypeId();
        Boolean isPrivate = queryVo.getIsPrivate();
        String start = queryVo.getStart();
        String end = queryVo.getEnd();
        String commentUserId = queryVo.getUserId();
        String value = queryVo.getValue();

        Query query = new Query();
        if (!StringUtils.isEmpty(typeId)) {
            query.addCriteria(Criteria.where("typeId").is(typeId));
        }
        if (!StringUtils.isEmpty(typePId)) {
            query.addCriteria(Criteria.where("parentTypeId").is(typePId));
        }
        if (!StringUtils.isEmpty(commentUserId)) {
            query.addCriteria(Criteria.where("userId").is(commentUserId));
        }
        query.addCriteria(Criteria.where("isDeleted").is(false));
        if (isPrivate != null) {
            query.addCriteria(Criteria.where("isPrivate").is(isPrivate));
        }
        if (!StringUtils.isEmpty(start) && StringUtils.isEmpty(end)) { // 只有start
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start)));
        } else if (StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 只有end
            query.addCriteria(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end)));
        } else if (!StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 有start有end
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start))
                    .andOperator(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end))));
        }
        if (!StringUtils.isEmpty(value)) {
            Pattern pattern = Pattern.compile("^.*" + value + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("content").regex(pattern));
        }
        //获取总数
        long total = mongoTemplate.count(query, CommentPost.class);

        // 分页
        // 按照最新发布时间降序排序
        Sort sort = Sort.by(Sort.Direction.DESC, "gmtCreate");
        Pageable pageable = PageRequest.of(page - 1, limit, sort);
        query.with(pageable);
        List<CommentPost> commentPosts = mongoTemplate.find(query, CommentPost.class);
        //获取详细信息
        for (CommentPost commentPost : commentPosts) {
            String hashKey = COMMENT_POST + commentPost.getId();
            getInfo(commentPost, hashKey);
        }
        PageResult pageResult = new PageResult(total, commentPosts.size(), commentPosts, page);   //赋值发起查询的用户与帖子相关信息
        if (!"".equals(userId)) {
            String likeSKey = COMMENT_POST_USER_LIKE + userId;
            String collectSKey = COMMENT_POST_USER_COLLECT + userId;
            for (Object record : pageResult.getRecords()) {
                //赋值发起查询的用户与帖子相关信息
                commentService.setUserInfo(record, ((CommentPost) record).getId(), likeSKey, collectSKey);
            }
        }

        return pageResult;
    }

    @Override
    public CommentPost getPostByPostId(Object id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        CommentPost post = mongoTemplate.findOne(query, CommentPost.class);
        if(post==null) {
            throw new BaiYunException(ResultCode.ERROR,MessageConstant.VALIDATEPOST_ERROR);
        }
        return post;
    }
    @Override
    public PageResult getCollectedPostListByToken(String userId, Integer page, Integer limit) {
        Set postIds = redisTemplate.opsForSet().members(COMMENT_POST_USER_COLLECT+userId);
        if (postIds == null || postIds.size() == 0) {
            return null;
        }
        // 计算分页的起始和结束索引
        int startIndex = (page - 1) * limit;
        int endIndex = Math.min(startIndex + limit, postIds.size());
        // 返回当前页的帖子列表
        List list = new ArrayList<>(postIds);
        List subList = list.subList(startIndex, endIndex);
        ArrayList<CommentPost> commentPosts = new ArrayList<>();
        for (Object postId : subList) {
            CommentPost post = null;
            try {
                post = getPostInfoByTokenAndPostId(userId, postId);
            } catch (Exception e) {
                commentPosts.add(new CommentPost());
                continue;
            }
            commentPosts.add(post);
        }

        PageResult pageResult = new PageResult((long) postIds.size(),commentPosts.size(),commentPosts,page);
        return pageResult;
    }
    @Override
    public PageResult getLikedPostListByToken(String userId, Integer page, Integer limit) {
        Set postIds = redisTemplate.opsForSet().members(COMMENT_POST_USER_LIKE+userId);
        if (postIds == null || postIds.size() == 0) {
            return null;
        }
        // 计算分页的起始和结束索引
        int startIndex = (page - 1) * limit;
        int endIndex = Math.min(startIndex + limit, postIds.size());
        // 返回当前页的帖子列表
        List list = new ArrayList<>(postIds);
        List subList = list.subList(startIndex, endIndex);
        ArrayList<CommentPost> commentPosts = new ArrayList<>();
        for (Object postId : subList) {
            CommentPost post = null;
            try {
                post = getPostInfoByTokenAndPostId(userId, postId);
            } catch (Exception e) {
                commentPosts.add(new CommentPost());
                continue;
            }
            commentPosts.add(post);
        }

        PageResult pageResult = new PageResult((long) postIds.size(),commentPosts.size(),commentPosts,page);
        return pageResult;
    }

    //TODO 新增缓存层优化查询数据
    @Override
    public CommentPost getPostInfoByTokenAndPostId(String userId, Object id) {
//        //设置缓存的KEY
//        String key = CACHE_COMMENT_KEY + userId;
//        //先从redis中查询,判断缓存是否存在
//        String commentJSON = stringRedisTemplate.opsForValue().get(key);
//        //存在
//        if (!StringUtils.isEmpty(commentJSON)){
//            //转成对应的数据类型并返回
//            return JSONUtil.toBean(commentJSON,CommentPost.class);
//        }
//
//        //不存在则从Mongodb数据库从查询
//        Query query = new Query();
//        query.addCriteria(Criteria.where("_id").is(id));
//        query.addCriteria(Criteria.where("isDeleted").is(false));
//        CommentPost post = mongoTemplate.findOne(query, CommentPost.class);
//        if (post == null) {
//            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATEPOST_ERROR);
//        }
//        String likeSKey = COMMENT_POST_USER_LIKE + userId;
//        String collectSKey = COMMENT_POST_USER_COLLECT + userId;
//        String hashKey = COMMENT_POST + post.getId();
//        getInfo(post, likeSKey,collectSKey, hashKey);
//        return post;
        String key = COMMENT_POST_INFO + id;
        CommentPost commentPost = redisUtils.queryByThrough(key, CommentPost.class, userId, id1 -> {
            Query query = new Query();
            query.addCriteria(Criteria.where("_id").is(id));
            query.addCriteria(Criteria.where("isDeleted").is(false));
            CommentPost post = mongoTemplate.findOne(query, CommentPost.class);
            if (post == null) {
                throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATEPOST_ERROR);
            }
            String hashKey = COMMENT_POST + post.getId();
            getInfo(post, hashKey);
            return post;
        }, COMMENT_INFO_TTL, TimeUnit.MINUTES);
        //赋值发起查询的用户与帖子相关信息
        if (!"".equals(userId)) {
            String likeSKey = COMMENT_POST_USER_LIKE + userId;
            String collectSKey = COMMENT_POST_USER_COLLECT + userId;
            commentService.setUserInfo(commentPost, commentPost.getId(), likeSKey, collectSKey);
        }
        return commentPost;
    }




    /**
     * 获取评论数量，
     * 评论相关信息，如点赞量，是否点赞过，收藏量，是否收藏过，用户信息等
     *
     */
    @Override
    public PageResult getPostListByCommentQueryVoAndTokenOrderByLike(String userId, Integer page, Integer limit, CommentQueryVo queryVo) {
        String typeId = queryVo.getTypeId();
        String typePId = queryVo.getPTypeId();
        Boolean isPrivate = queryVo.getIsPrivate();
        String start = queryVo.getStart();
        String end = queryVo.getEnd();
        String commentUserId = queryVo.getUserId();
        String value = queryVo.getValue();

        Query query = new Query();
        if (!StringUtils.isEmpty(typeId)) {
            query.addCriteria(Criteria.where("typeId").is(typeId));
        }
        if (!StringUtils.isEmpty(typePId)) {
            query.addCriteria(Criteria.where("parentTypeId").is(typePId));
        }
        if (!StringUtils.isEmpty(commentUserId)) {
            query.addCriteria(Criteria.where("userId").is(commentUserId));
        }
        query.addCriteria(Criteria.where("isDeleted").is(false));
        if (isPrivate != null) {
            query.addCriteria(Criteria.where("isPrivate").is(isPrivate));
        }
        if (!StringUtils.isEmpty(start) && StringUtils.isEmpty(end)) { // 只有start
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start)));
        } else if (StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 只有end
            query.addCriteria(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end)));
        } else if (!StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 有start有end
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start))
                    .andOperator(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end))));
        }
        if (!StringUtils.isEmpty(value)) {
            Pattern pattern = Pattern.compile("^.*" + value + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("content").regex(pattern));
        }
        List<CommentPost> commentPosts = mongoTemplate.find(query, CommentPost.class);
        //获取排名信息并分页
        String likeSKey = COMMENT_POST_USER_LIKE + userId;
        String collectSKey = COMMENT_POST_USER_COLLECT + userId;
        String hashKey = "";
        for (CommentPost commentPostAll : commentPosts) {
            hashKey = COMMENT_POST + commentPostAll.getId();
            // 从Redis获取点赞数并设置到帖子对象中
            Integer likes = (Integer) redisTemplate.opsForHash().get(hashKey, _LIKE);
            if (likes == null) {
                likes = 0;
            }
            commentPostAll.setLikes(likes);
        }

        // 对帖子列表按照点赞数进行降序排序
        commentPosts.sort((o1, o2) -> {
            // 首先比较点赞数，实现降序排序
            int likesComparison = o2.getLikes().compareTo(o1.getLikes());
            if (likesComparison == 0) {
                // 如果点赞数相同，则比较创建时间，实现降序排序
                return o2.getGmtCreate().compareTo(o1.getGmtCreate());
            }
            return likesComparison;
        });
        // 计算分页的起始和结束索引
        int startIndex = (page - 1) * limit;
        int endIndex = Math.min(startIndex + limit, commentPosts.size());
        // 返回当前页的帖子列表
        List<CommentPost> subList = commentPosts.subList(startIndex, endIndex);
        for (CommentPost commentPost : subList) {
            hashKey = COMMENT_POST + commentPost.getId();
            //查询帖子详情
            getInfo(commentPost, hashKey);
        }
        PageResult pageResult = new PageResult((long) commentPosts.size(), subList.size(), subList, page);
        //TODO 此处缓存pageResult
        for (Object record : pageResult.getRecords()) {
            //赋值发起查询的用户与帖子相关信息
            commentService.setUserInfo(record, ((CommentPost) record).getId(), likeSKey, collectSKey);
        }
        return pageResult;
    }


    /**
     * 获取评论数量，
     * 评论相关信息，如点赞量，是否点赞过，收藏量，是否收藏过，用户信息等
     *
     * @param commentPost 评论
     * @param hashKey
     */
    private void getInfo(CommentPost commentPost, String hashKey) {
        String postUserId = commentPost.getUserId();
        String postId = commentPost.getId();
        // 查询帖子发布者的信息
        CompletableFuture<UserInfoVo> userFuture = CompletableFuture.supplyAsync(() -> {
            try {
                UserInfoVo user = JSON.parseObject(JSON.toJSONString(userClient.getUserInfoById(postUserId).getData().get("user")), UserInfoVo.class);
                if (user == null) {
                    throw new BaiYunException(ResultCode.ERROR, MessageConstant.QUERY_USERINFO_FAIL);
                }
                return user;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, threadPoolExecutor);

        // 获取评论数量
        CompletableFuture<Integer> commentsCountFuture = CompletableFuture.supplyAsync(() -> {
            return commentService.getCommentCount(postId);
        }, threadPoolExecutor);

        // 获取评论点赞数量
        CompletableFuture<Integer> likeCountFuture = CompletableFuture.supplyAsync(() -> {
            return (Integer) redisTemplate.opsForHash().get(hashKey, _LIKE);
        }, threadPoolExecutor);

        // 获取评论收藏数量
        CompletableFuture<Integer> collectCountFuture = CompletableFuture.supplyAsync(() -> {
            return (Integer) redisTemplate.opsForHash().get(hashKey, _COLLECT);
        }, threadPoolExecutor);

        // 获取评论浏览数量
        CompletableFuture<Integer> viewCountFuture = CompletableFuture.supplyAsync(() -> {
            return (Integer) redisTemplate.opsForHash().get(hashKey, _VIEW);
        }, threadPoolExecutor);


        CompletableFuture.allOf(userFuture, commentsCountFuture, likeCountFuture, collectCountFuture, viewCountFuture).join();

        try {
            UserInfoVo user = userFuture.get();
            commentPost.setUserUseTitle(user.getTitles());
            commentPost.setUserName(user.getNickname());
            commentPost.setUserAvatar(user.getAvatar());
            commentPost.setIsJoin(user.getIsJoin());
            commentPost.setComments(commentsCountFuture.get());
            commentPost.setLikes(likeCountFuture.get());
            commentPost.setCollects(collectCountFuture.get());
            commentPost.setViews(viewCountFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }



}
